package cn.tedu.charging.device.warm;

import cn.tedu.charging.common.pojo.po.ChargingStationPO;
import cn.tedu.charging.device.mapper.StationMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.dao.DataAccessException;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * 预热类 专门负责 将station数据预热到redis
 */
@Component
@Slf4j
public class StationWarmUp implements ApplicationRunner {
    @Autowired
    private StationMapper stationMapper;
    @Resource(name = "redis01")
    private RedisTemplate redisTemplate;

    /**
    * 在当前springboot程序启动、容器创建结束时，run被调用
    * */
    public void run(ApplicationArguments args) throws Exception {
        log.debug("开始缓存预热。");
        //1.检查开关
        String warmupSwitch = "station_warm_up";
        boolean execute = checkWarmupExecute(warmupSwitch);
        if (!execute){
            log.debug("缓存预热开关未打开,不执行预热");
            return;
        }else{
            log.debug("缓存预热开关已打开,开始执行预热");
            batchWarmup(1000L);
        }
    }
    private void batchWarmup(Long batchSize) {
        Long total = stationMapper.selectCount(null);
        long loopSize = total%batchSize == 0 ? total/batchSize : total/batchSize + 1;
        for (int i = 0; i < loopSize; i++) {
            // 查询每批的1000条数据 分页读 0~1000 1001~2000
            // pageSize=1000 pageNo=1~loopSize limit 0,1000 limit 1000,1000 limit 2000,1000
            // 拼接limit from(i*batchSize),size(batchSize)
            QueryWrapper<ChargingStationPO> queryWrapper = new QueryWrapper<>();
            // 不填写查询条件,只填写limit
            queryWrapper.last("limit " + i*batchSize + "," + batchSize);
            List<ChargingStationPO> pos = stationMapper.selectList(queryWrapper);
            saveRedisCache(pos);
        }
    }
    private void saveRedisCache(List<ChargingStationPO> pos) {
        List results = redisTemplate.executePipelined(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
                //使用pipeline
                for (ChargingStationPO po : pos) {
                    String stationKey = "charging:station:cache:" + po.getId();
                    redisTemplate.opsForValue().set(stationKey, po);
                    //UNDO 判断 station所属行政区域 cityCode查询行政区域名称
                    String geoKey = "beijing_stations";
                    redisTemplate.opsForGeo().add(geoKey,
                            new Point(po.getStationLng().doubleValue(),po.getStationLat().doubleValue()),
                            po.getId());
                }
                return null;
            }
        });
    }
    private boolean checkWarmupExecute(String warmUpSwitch) {
        Long num = redisTemplate.opsForValue().increment(warmUpSwitch);
        return num == 1;
    }
}
